import * as fs from 'fs';
import { $r } from '../utils';
import * as vscode from 'vscode';
import { PackageMessage } from "../models/uiMessage";
import { dependencie, tomlFile } from "../models/tomlFile";

export class tomlLoader {
    private packages: dependencie[] = [];
    private readonly tomlFilePath: string;
    private tomlObject: tomlFile | undefined = undefined;
    constructor(tomlFilePath: string) {
        this.tomlFilePath = tomlFilePath;
    }

    loadFile() {
        try {
            const content = fs.readFileSync(this.tomlFilePath, 'utf8');
            this.tomlObject = {};
            const lines = content.split('\n');
            let currentSection = '';
            for (const line of lines) {
                const trimmedLine = line.trim();
                if (trimmedLine.startsWith('[') && trimmedLine.endsWith(']')) {
                    const sectionName = trimmedLine.slice(1, -1).trim();
                    currentSection = sectionName;
                    this.tomlObject[currentSection] = {};
                } else if (trimmedLine.includes('=')) {
                    let [key, value] = trimmedLine.split('=').map((item) => item.trim());
                    if (trimmedLine.replace(/ /gi, '').replace('=', '').length > `${key}${value}`.length) {
                        value = trimmedLine.replace(key, '').replace('=', '').replace(/ /gi, '');
                    }
                    if (currentSection && key && value) {
                        this.tomlObject[currentSection][key] = this.parseValue(value);
                    }
                }
            }
        } catch (e) {
            vscode.window.showErrorMessage($r('loadTomlFailed', e));
        }
    }

    getPackages() {
        try {
            if (this.tomlObject) {
                const dependencies = this.tomlObject['dependencies'],
                keys = Object.keys(dependencies), values: string[] = Object.values(dependencies);
                for (let i = 0; i < keys.length; i++) {
                    if (values[i].startsWith('{') && values[i].endsWith('}')) {
                        const gitMatch = /git\s*=\s*"([^"]+)"/.exec(values[i]);
                        const branchMatch = /branch\s*=\s*"([^"]+)"/.exec(values[i]);
                        const versionMatch = /version\s*=\s*"([^"]+)"/.exec(values[i]);
                        const row: dependencie = {
                            packageName: keys[i],
                            packageUrl: {
                                git: gitMatch?.[1]?.valueOf() ?? '',
                                branch: versionMatch?.[1]?.valueOf() ?? '',
                                version: branchMatch?.[1]?.valueOf() ?? values[i]
                            }
                        };
                        this.packages.push(row);
                    } else {
                        const row: dependencie = {
                            packageName: keys[i],
                            packageUrl: values[i]
                        };
                        this.packages.push(row);
                    }
                }
            }
        } catch (e) {
            vscode.window.showErrorMessage($r('loadDepFailed', e));
        }
        return this.packages;
    }

    addNode(message: PackageMessage) {
        if (message.packageUrl) {
            this.packages.push({
                packageName: message.projectName,
                packageUrl: {
                    git: message.packageUrl ?? "",
                    branch: message.packageBranch ?? "",
                    version: message.packageVersion
                }
            });
        } else {
            this.packages.push({
                packageName: message.projectName,
                packageUrl: message.packageVersion
            });
        }
    }

    updateNode(message: PackageMessage) {
        const update = this.packages.find((i) => i.packageName.toLowerCase() === message.projectName.toLowerCase());
        if (update) {
            if (typeof update.packageUrl === 'string') {
                update.packageUrl = message.packageVersion;
            } else {
                update.packageUrl.git = message.packageUrl ?? "";
                update.packageUrl.version = message.packageVersion;
                update.packageUrl.branch = message.packageBranch ?? "";
            }
        }
    }

    rmeoveNode(message: PackageMessage) {
        const index = this.packages.findIndex((i) => i.packageName.toLowerCase() === message.projectName.toLowerCase());
        if (index !== -1) {
            this.packages.splice(index, 1);
        }
    }

    applyNow() {
        try {
            const data = fs.readFileSync(this.tomlFilePath, 'utf8'),
             lines = data.split('\n');
            let inDependenciesSection = false;
            for (let i = 0; i < lines.length; i++) {
                if (lines[i]?.trim() === '[dependencies]') {
                    inDependenciesSection = true;
                }
                if (inDependenciesSection) {
                    if (!lines[i].startsWith('[')) {
                        lines.splice(i, 1);
                    }
                    if (lines[i]?.trim() === '' || (lines[i]?.trim() !== '[dependencies]') && lines[i]?.startsWith('[')) {
                        inDependenciesSection = false;
                        break;
                    }
                }
            }
            let newDependencies = '';
            for (const item of this.packages) {
                const content = (typeof item.packageUrl !== 'string') ? `${item.packageName} = {git = "${item.packageUrl.git ?? ""}", branch = "${item.packageUrl.branch ?? ""}", version = "${item.packageUrl.version}"}` : `${item.packageName} = "${item.packageUrl}"`;
                newDependencies += `  ${content}\n`;
            }
            const dependenciesIndex = lines.findIndex(line => line.trim() === '[dependencies]');
            lines.splice(dependenciesIndex + 1, 0, newDependencies);
            fs.writeFileSync(this.tomlFilePath, lines.join('\n'), 'utf8');
        } catch (e) {
            vscode.window.showErrorMessage($r('saveTomlFailed', e));
        }
    }

    private parseValue(value: string): string | number | boolean {
        try {
            if (value.startsWith('"') && value.endsWith('"')) {
                let str = value.slice(1, -1);
                if (str.startsWith('{') && str.endsWith('}')) {
                    str = value.slice(1, -1);
                }
                return str;
            } else if (value === 'true') {
                return true;
            } else if (value === 'false') {
                return false;
            } else if (!isNaN(Number(value))) {
                return Number(value);
            } else {
                return value;
            }
        } catch (e) {
            console.log(e);
            return value;
        }
    }
}